package org.dromara.nursing.service.impl;

import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.dromara.nursing.domain.bo.MsOccupancyStatisticsBo;
import org.dromara.nursing.domain.vo.MsOccupancyStatisticsVo;
import org.dromara.nursing.domain.MsOccupancyStatistics;
import org.dromara.nursing.domain.BedInfo;
import org.dromara.nursing.domain.AdmissionContract;
import org.dromara.nursing.mapper.MsOccupancyStatisticsMapper;
import org.dromara.nursing.mapper.BedInfoMapper;
import org.dromara.nursing.mapper.ElderBasicMapper;
import org.dromara.nursing.mapper.AdmissionContractMapper;
import org.dromara.nursing.service.IMsOccupancyStatisticsService;

import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.Date;
import java.util.Calendar;
import java.text.SimpleDateFormat;
import java.util.ArrayList;

/**
 * 入住率统计Service业务层处理
 *
 * @author Lion Li
 * @date 2025-04-23
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class MsOccupancyStatisticsServiceImpl implements IMsOccupancyStatisticsService {

    private final MsOccupancyStatisticsMapper baseMapper;
    private final BedInfoMapper bedInfoMapper;
    private final ElderBasicMapper elderBasicMapper;
    private final AdmissionContractMapper admissionContractMapper;

    /**
     * 查询入住率统计
     *
     * @param statId 主键
     * @return 入住率统计
     */
    @Override
    public MsOccupancyStatisticsVo queryById(Long statId){
        return baseMapper.selectVoById(statId);
    }

    /**
     * 分页查询入住率统计列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 入住率统计分页列表
     */
    @Override
    public TableDataInfo<MsOccupancyStatisticsVo> queryPageList(MsOccupancyStatisticsBo bo, PageQuery pageQuery) {
        try {
            // 如果需要实时统计，则直接返回实时统计数据
            if (bo.getParams() != null && "1".equals(bo.getParams().get("realtime"))) {
                // 生成实时统计数据
                MsOccupancyStatisticsVo realtimeStats = generateRealtimeStatistics();

                // 创建一个新的Page对象
                Page<MsOccupancyStatisticsVo> result = new Page<>();

                // 创建一个新的ArrayList来存储记录
                List<MsOccupancyStatisticsVo> records = new ArrayList<>();
                records.add(realtimeStats);

                // 设置记录和总数
                result.setRecords(records);
                result.setTotal(1);

                return TableDataInfo.build(result);
            }

            // 否则查询数据库中的记录
            LambdaQueryWrapper<MsOccupancyStatistics> lqw = buildQueryWrapper(bo);
            Page<MsOccupancyStatisticsVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
            return TableDataInfo.build(result);
        } catch (Exception e) {
            log.error("查询入住率统计列表失败", e);
            // 出现异常时，尝试返回实时统计数据
            try {
                MsOccupancyStatisticsVo realtimeStats = generateRealtimeStatistics();
                Page<MsOccupancyStatisticsVo> result = new Page<>();
                List<MsOccupancyStatisticsVo> records = new ArrayList<>();
                records.add(realtimeStats);
                result.setRecords(records);
                result.setTotal(1);
                return TableDataInfo.build(result);
            } catch (Exception ex) {
                log.error("生成实时统计数据失败", ex);
                return TableDataInfo.build(new Page<>());
            }
        }
    }

    /**
     * 查询符合条件的入住率统计列表
     *
     * @param bo 查询条件
     * @return 入住率统计列表
     */
    @Override
    public List<MsOccupancyStatisticsVo> queryList(MsOccupancyStatisticsBo bo) {
        try {
            // 如果需要实时统计，则直接返回实时统计数据
            if (bo.getParams() != null && "1".equals(bo.getParams().get("realtime"))) {
                // 生成实时统计数据
                MsOccupancyStatisticsVo realtimeStats = generateRealtimeStatistics();

                // 创建一个新的ArrayList来存储记录
                List<MsOccupancyStatisticsVo> list = new ArrayList<>();
                list.add(realtimeStats);

                return list;
            }

            // 否则查询数据库中的记录
            LambdaQueryWrapper<MsOccupancyStatistics> lqw = buildQueryWrapper(bo);
            return baseMapper.selectVoList(lqw);
        } catch (Exception e) {
            log.error("查询入住率统计列表失败", e);
            // 出现异常时，尝试返回实时统计数据
            try {
                MsOccupancyStatisticsVo realtimeStats = generateRealtimeStatistics();
                List<MsOccupancyStatisticsVo> list = new ArrayList<>();
                list.add(realtimeStats);
                return list;
            } catch (Exception ex) {
                log.error("生成实时统计数据失败", ex);
                return new ArrayList<>();
            }
        }
    }

    private LambdaQueryWrapper<MsOccupancyStatistics> buildQueryWrapper(MsOccupancyStatisticsBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<MsOccupancyStatistics> lqw = Wrappers.lambdaQuery();
        lqw.orderByAsc(MsOccupancyStatistics::getStatId);
        lqw.eq(bo.getStatDate() != null, MsOccupancyStatistics::getStatDate, bo.getStatDate());
        return lqw;
    }

    /**
     * 生成实时统计数据
     *
     * @return 实时统计数据
     */
    private MsOccupancyStatisticsVo generateRealtimeStatistics() {
        log.info("开始生成实时入住率统计数据");

        MsOccupancyStatisticsVo vo = new MsOccupancyStatisticsVo();

        try {
            // 获取总床位数
            long totalBeds = bedInfoMapper.selectTotalBedCount();
            log.info("总床位数: {}", totalBeds);

            // 获取已占用床位数
            LambdaQueryWrapper<BedInfo> occupiedQuery = Wrappers.lambdaQuery();
            occupiedQuery.eq(BedInfo::getBedStatus, "已占用");
            long occupiedBeds = bedInfoMapper.selectCount(occupiedQuery);
            log.info("已占用床位数: {}", occupiedBeds);

            // 获取维修中床位数
            LambdaQueryWrapper<BedInfo> maintenanceQuery = Wrappers.lambdaQuery();
            maintenanceQuery.eq(BedInfo::getBedStatus, "维修中");
            long maintenanceBeds = bedInfoMapper.selectCount(maintenanceQuery);
            log.info("维修中床位数: {}", maintenanceBeds);

            // 计算可用床位数
            long availableBeds = totalBeds - occupiedBeds - maintenanceBeds;
            log.info("可用床位数: {}", availableBeds);

            // 计算入住率
            double occupancyRate = totalBeds > 0 ? (double) occupiedBeds / totalBeds * 100 : 0;
            log.info("入住率: {}%", occupancyRate);

            // 获取在院老人数量
            long totalElders = elderBasicMapper.selectActiveElderCount();
            log.info("在院老人数量: {}", totalElders);

            // 设置统计日期
            Date now = new Date();
            vo.setStatDate(now);

            // 设置统计月份和年份
            Calendar cal = Calendar.getInstance();
            cal.setTime(now);
            vo.setStatMonth(new SimpleDateFormat("yyyy-MM").format(now));
            vo.setStatYear((long) cal.get(Calendar.YEAR));

            // 设置统计数据
            vo.setTotalBeds(totalBeds);
            vo.setOccupiedBeds(occupiedBeds);
            vo.setAvailableBeds(availableBeds);
            vo.setMaintenanceBeds(maintenanceBeds);
            vo.setOccupancyRate((long) Math.round(occupancyRate));

            // 获取本月新入住人数（从入住合同表统计）
            Calendar firstDayOfMonth = Calendar.getInstance();
            firstDayOfMonth.set(Calendar.DAY_OF_MONTH, 1);
            firstDayOfMonth.set(Calendar.HOUR_OF_DAY, 0);
            firstDayOfMonth.set(Calendar.MINUTE, 0);
            firstDayOfMonth.set(Calendar.SECOND, 0);
            firstDayOfMonth.set(Calendar.MILLISECOND, 0);

            LambdaQueryWrapper<AdmissionContract> newAdmissionsQuery = Wrappers.lambdaQuery();
            newAdmissionsQuery.ge(AdmissionContract::getStartDate, firstDayOfMonth.getTime());
            newAdmissionsQuery.eq(AdmissionContract::getContractStatus, "有效");
            newAdmissionsQuery.eq(AdmissionContract::getIsCheckContract, "1"); // 已审核
            long newAdmissions = admissionContractMapper.selectCount(newAdmissionsQuery);
            log.info("本月新入住人数: {}", newAdmissions);

            // 获取本月退住人数（从合同表统计终止的合同）
            LambdaQueryWrapper<AdmissionContract> dischargesQuery = Wrappers.lambdaQuery();
            dischargesQuery.ge(AdmissionContract::getUpdateTime, firstDayOfMonth.getTime());
            dischargesQuery.eq(AdmissionContract::getContractStatus, "终止");
            long discharges = admissionContractMapper.selectCount(dischargesQuery);
            log.info("本月退住人数: {}", discharges);

            // 计算平均入住天数（从合同表计算）
            long avgStayDays = 0;
            try {
                avgStayDays = admissionContractMapper.selectAvgStayDays();
                log.info("平均入住天数: {}", avgStayDays);
            } catch (Exception e) {
                log.error("计算平均入住天数失败", e);
                avgStayDays = 180; // 默认值
            }

            // 获取等待入住人数（从待审核的合同表统计）
            LambdaQueryWrapper<AdmissionContract> waitingQuery = Wrappers.lambdaQuery();
            waitingQuery.eq(AdmissionContract::getIsCheckContract, "0"); // 未审核
            waitingQuery.eq(AdmissionContract::getContractStatus, "有效");
            long waitingListCount = admissionContractMapper.selectCount(waitingQuery);
            log.info("等待入住人数: {}", waitingListCount);

            // 设置统计数据
            vo.setNewAdmissions(newAdmissions);
            vo.setDischarges(discharges);
            vo.setAvgStayDays(avgStayDays);
            vo.setWaitingListCount(waitingListCount);

            log.info("实时入住率统计数据生成成功");
        } catch (Exception e) {
            log.error("生成实时入住率统计数据失败", e);
        }

        return vo;
    }

    /**
     * 新增入住率统计
     *
     * @param bo 入住率统计
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(MsOccupancyStatisticsBo bo) {
        MsOccupancyStatistics add = MapstructUtils.convert(bo, MsOccupancyStatistics.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setStatId(add.getStatId());
        }
        return flag;
    }

    /**
     * 修改入住率统计
     *
     * @param bo 入住率统计
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(MsOccupancyStatisticsBo bo) {
        MsOccupancyStatistics update = MapstructUtils.convert(bo, MsOccupancyStatistics.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(MsOccupancyStatistics entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除入住率统计信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }
}
